#include "standard-table-model.h"

StandardTableModel::StandardTableModel(QObject *parent) :
    QAbstractTableModel(parent)
{
}

int StandardTableModel::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);
    return m_itemData.size();
}

int StandardTableModel::columnCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);
    return m_headerData.size();
}

QVariant StandardTableModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
        return QVariant();
    return m_itemData.at(index.row()).at(index.column()).value(role);
}

QVariant StandardTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if ((orientation == Qt::Horizontal && (section < 0 || section >= columnCount())) ||
        (orientation == Qt::Vertical && (section < 0 || section >= rowCount())))
        return QVariant();

    if (orientation == Qt::Horizontal)
        return m_headerData.at(section).value(role);
    else
    {
        if (role == Qt::DisplayRole)
            return section+1;
        else
            return QVariant();
    }
}

bool StandardTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (!index.isValid())
        return false;
    m_itemData[index.row()][index.column()].insert(role, value);
    emit dataChanged(index, index);
    return true;
}

bool StandardTableModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role)
{
    if ((orientation == Qt::Horizontal && (section < 0 || section >= columnCount())) || orientation == Qt::Vertical)
        return false;

    m_headerData[section].insert(role, value);
    return true;
}

void StandardTableModel::setRowCount(int rows)
{
    int difference = rows - rowCount();
    if (difference == 0)
        return;
    else if (difference > 0)
    {
        beginInsertRows(QModelIndex(), rowCount(), rowCount()-1+difference);
        while (difference > 0)
        {
            QList<QHash<int,QVariant>> dataList;
            for (int i = 0; i < columnCount(); i++)
                dataList.append(QHash<int,QVariant>());
            m_itemData.append(dataList);
            difference--;
        }
        endInsertRows();
    }
    else
    {
        beginRemoveRows(QModelIndex(), rowCount()-1+difference, rowCount()-1);
        while (difference < 0)
        {
            m_itemData.removeLast();
            difference++;
        }
        endRemoveRows();
    }
}

void StandardTableModel::setColumnCount(int columns)
{
    int difference = columns - columnCount();
    if (difference == 0)
        return;
    else if (difference > 0)
    {
        beginInsertColumns(QModelIndex(), columnCount(), columnCount()-1+difference);
        for (int i = 0; i < difference; i++)
            m_headerData.append(QHash<int,QVariant>());
        for (int j = 0; j < rowCount(); j++)
        {
            for (int k = 0; k < difference; k++)
                m_itemData[j].append(QHash<int,QVariant>());
        }
        endInsertColumns();
    }
    else
    {
        beginRemoveColumns(QModelIndex(), columnCount()-1+difference, columnCount()-1);
        for (int i = difference; i < 0; i++)
            m_headerData.removeLast();
        for (int j = 0; j < rowCount(); j++)
        {
            for (int k = difference; k < 0; k++)
                m_itemData[k].removeLast();
        }
        endRemoveColumns();
    }
}

void StandardTableModel::appendRow()
{
    QVariantList dataList;
    for (int i = 0; i < columnCount(); i++)
        dataList.append(QVariant());
    appendRow(dataList);
}

void StandardTableModel::appendRow(QVariantList dataList)
{
    insertRow(rowCount(), dataList);
}

void StandardTableModel::appendColumn(QVariantList dataList)
{
    insertColumn(columnCount(), dataList);
}

void StandardTableModel::insertRow(int row, QVariantList dataList)
{
    beginInsertRows(QModelIndex(), row, row);
    QList<QHash<int,QVariant>> cells;
    for (int i = 0; i < dataList.size(); i++)
    {
        QHash<int,QVariant> values;
        values.insert(Qt::DisplayRole, dataList.at(i));
        cells.append(values);
    }
    m_itemData.insert(row, cells);
    endInsertRows();
}

void StandardTableModel::insertColumn(int column, QVariantList dataList)
{
    beginInsertColumns(QModelIndex(), column, column);
    m_headerData.insert(column, QHash<int,QVariant>());
    for (int i = 0; i < rowCount(); i++)
    {
        QHash<int,QVariant> values;
        values.insert(Qt::DisplayRole, dataList.at(i));
        m_itemData[i].insert(column, values);
    }
    endInsertRows();
}

bool StandardTableModel::removeRows (int row, int count, const QModelIndex &parent)
{
    beginRemoveRows(parent, row, row + count - 1);
    for (; count > 0; count--)
        m_itemData.removeAt(row + count - 1);
    endRemoveRows();
    return true;
}

void StandardTableModel::removeRows (const QList<int> &rows)
{
    beginResetModel();
    for (int i = rows.size()-1; i >= 0; i--)
        m_itemData.removeAt(rows.at(i));
    endResetModel();
}

void StandardTableModel::removeRows(const QVariantList &rows)
{
    beginResetModel();
    for (int i = rows.size()-1; i >= 0; i--)
        m_itemData.removeAt(rows.at(i).toInt());
    endResetModel();
}

void StandardTableModel::swapColumns(int firstColumn, int secondColumn)
{
    if (firstColumn == secondColumn)
        return;

    beginResetModel();
    QHash<int,QVariant> fieldData;
    for (int i = 0; i < rowCount(); i++)
    {
        fieldData = m_itemData.at(i).at(firstColumn);
        m_itemData[i][firstColumn] = m_itemData.at(i).at(secondColumn);
        m_itemData[i][secondColumn] = fieldData;
    }

    if (!m_headerData.isEmpty())
    {
        fieldData = m_headerData.at(firstColumn);
        m_headerData[firstColumn] = m_headerData.at(secondColumn);
        m_headerData[secondColumn] = fieldData;
    }

    endResetModel();
}

bool StandardTableModel::removeColumns (int column, int count, const QModelIndex &parent)
{
    beginRemoveColumns(parent, column, column + count - 1);

    for (int i = 0; i < rowCount(); i++)
    {
        for (int j = count; j > 0; j--)
            m_itemData[i].removeAt(column + j - 1);
    }

    for (int k = count; k > 0; k--)
        m_headerData.removeAt(column + k - 1);

    endRemoveColumns();
    return true;
}

bool StandardTableModel::insertRows (int row, int count, const QModelIndex &parent)
{
    beginInsertRows(parent, row, row + count - 1);
    for (int i = 0; i < count; i++)
    {
        QList< QHash<int,QVariant> > emptyRow;
        for (int j = 0; j < columnCount(); j++)
            emptyRow.append(QHash<int,QVariant>());
        m_itemData.insert(row + i, emptyRow);
    }
    endInsertRows();
    return true;
}

bool StandardTableModel::insertColumns(int column, int count, const QModelIndex &parent)
{
    beginInsertColumns(parent, column, column + count - 1);
    for (int i = 0; i < count; i++)
        m_headerData.insert(column + i, QHash<int,QVariant>());
    endInsertColumns();
    return true;
}

QList<QList<QHash<int,QVariant>>>& StandardTableModel::itemData()
{
    return m_itemData;
}

void StandardTableModel::clear()
{
    beginResetModel();
    m_itemData.clear();
    m_headerData.clear();
    endResetModel();
}

void StandardTableModel::beginResetModelSlot()
{
    beginResetModel();
}

void StandardTableModel::endResetModelSlot()
{
    endResetModel();
}
